/*
 *  ********************************************************************   **
 *  Copyright notice                                                       **
 *  **																	   **
 *  (c) 2003 Entagged Developpement Team				                   **
 *  http://www.sourceforge.net/projects/entagged                           **
 *  **																	   **
 *  All rights reserved                                                    **
 *  **																	   **
 *  This script is part of the Entagged project. The Entagged 			   **
 *  project is free software; you can redistribute it and/or modify        **
 *  it under the terms of the GNU General Public License as published by   **
 *  the Free Software Foundation; either version 2 of the License, or      **
 *  (at your option) any later version.                                    **
 *  **																	   **
 *  The GNU General Public License can be found at                         **
 *  http://www.gnu.org/copyleft/gpl.html.                                  **
 *  **																	   **
 *  This copyright notice MUST APPEAR in all copies of the file!           **
 *  ********************************************************************
 */
 
/*
This code was adapted from the rhythmbox-desklet, that is originally written in python.
The original code can be found here: 
http://gdesklets.gnomedesktop.org/categories.php?func=gd_show_app&gd_app_id=162
*/
package entagged.covers;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class AmazonCoverSource implements CoverSource {
	private static final String SOAP_ACTION = "SearchArtistRequest";
	private static final String SOAP_URL = "http://soap.amazon.com/onca/soap3";
	private static final Pattern SOAP_PATTERN = Pattern.compile(".+?ProductName.+?>(.+?)</ProductName.+?Artist .+?>(.+?)</Artist.+?ImageUrlSmall.+?>(.+?)</ImageUrlSmall.+?ImageUrlMedium.+?>(.+?)</ImageUrlMedium.+?ImageUrlLarge.+?>(.+?)</ImageUrlLarge.*");

	
	private String getSoapRequest(String artist, String album) {
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		sb.append("<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">");
		sb.append("<SOAP-ENV:Body>");
		sb.append("<ns1:ArtistSearchRequest xmlns:ns1=\"http://soap.amazon.com\" SOAP-ENC:root=\"1\">");
		sb.append("<v1>" + "<sort xsi:type=\"xsd:string\">+pmrank</sort>");
		sb.append("<artist xsi:type=\"xsd:string\">").append(artist).append("</artist>");
		sb.append("<devtag xsi:type=\"xsd:string\">D1R5WXCELBX4NF</devtag>");
		sb.append("<tag xsi:type=\"xsd:string\">accessonline</tag>");
		sb.append("<mode xsi:type=\"xsd:string\">music</mode>");
		sb.append("<keywords xsi:type=\"xsd:string\">").append(album).append("</keywords>");
		sb.append("<type xsi:type=\"xsd:string\">lite</type>");
		sb.append("<page xsi:type=\"xsd:int\">1</page>" + "</v1>");
		sb.append("</ns1:ArtistSearchRequest>" + "</SOAP-ENV:Body>");
		sb.append("</SOAP-ENV:Envelope>");
		
		return sb.toString();
	}
	
	private String sendSoapRequest(String request) throws IOException {
		//Set up the request
		HttpURLConnection httpConn = (HttpURLConnection) new URL(SOAP_URL).openConnection();
		httpConn.setRequestProperty("Content-Length", String.valueOf(request.length()));
		httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
		httpConn.setRequestProperty("SOAPAction", SOAP_ACTION);
		httpConn.setRequestMethod("POST");
		httpConn.setDoOutput(true);
		httpConn.setDoInput(true);

		//Send our xml request
		PrintWriter out = new PrintWriter(httpConn.getOutputStream());
		out.println(request);
		out.close();

		//Receive the answer
		BufferedReader in = new BufferedReader(new InputStreamReader(httpConn
				.getInputStream()));
		String inputLine;
		StringBuffer sb = new StringBuffer();
		while ((inputLine = in.readLine()) != null) {
			sb.append(inputLine);
		}
		in.close();
		
		return sb.toString();
	}
	
	private boolean isImageEmpty(String url) {
		try{
			HttpURLConnection httpConn = (HttpURLConnection) new URL(url).openConnection();
			return httpConn.getContentLength() == 807;
		} catch(IOException e) {
			return true;
		}
	}
	
	public List search(String artist, String album) throws CoverException {
		//List to store our results
		List list = new LinkedList();
		
		//Transform the artist and album strings to better search
		String nartist = Utils.normalize(artist);
		String nalbum = Utils.normalize(album);

		//Read the server answer, and clean up the answer
		String answer;
		try {
			answer = sendSoapRequest(getSoapRequest(nartist, nalbum));
		} catch(IOException e) {
			throw new CoverException(e.getMessage());
		}
		answer = answer.replaceAll("\n", "");
		answer = answer.replaceAll("&amp;", "&");
		
		//We parse the result and create the Coverresults
		//There may be several matches, so we parse every match, and offset the nswer to get more
		int nextSubIndex = 0;
		while (answer.length() > nextSubIndex) {
			Matcher matcher = SOAP_PATTERN.matcher(answer.substring(nextSubIndex));

			if (matcher.matches()) {
				//Retreive the best url (non-empty image)
				String bestUrl = "";
				for( int i = 5; i>=3; i--) {
					bestUrl = matcher.group(i);
					if(!isImageEmpty(bestUrl)) 
						break;
				}
				//Ensure the best url is non-empty
				if(bestUrl.equals(""))
					break;
				
				//new Cover(Artist, Album, Url)
				try {
					list.add(new Cover(matcher.group(2), matcher.group(1), new URL(bestUrl)));
				} catch(IOException e) {
					//Do not add the cover since we got an exception
				}

				nextSubIndex += matcher.end(matcher.groupCount());
			} else {
				break;
			}
		}
		return list;
	}
}
